{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Configurations for Colab"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "IN_COLAB = \"google.colab\" in sys.modules\n",
    "\n",
    "if IN_COLAB:\n",
    "    !apt install python-opengl\n",
    "    !apt install ffmpeg\n",
    "    !apt install xvfb\n",
    "    !pip install pyvirtualdisplay\n",
    "    !pip install gym[all]\n",
    "    from pyvirtualdisplay import Display\n",
    "    \n",
    "    # Start virtual display\n",
    "    dis = Display(visible=0, size=(400, 400))\n",
    "    dis.start()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 03. Prioritized Experience Replay (PER)\n",
    "\n",
    "[T. Schaul et al., \"Prioritized Experience Replay.\" arXiv preprint arXiv:1511.05952, 2015.](https://arxiv.org/pdf/1511.05952.pdf)\n",
    "\n",
    "Using a replay memory leads to design choices at two levels: which experiences to store, and which experiences to replay (and how to do so). This paper addresses only the latter: making the most effective use of the replay memory for learning, assuming that its contents are outside of our control.\n",
    "\n",
    "The central component of prioritized replay is the criterion by which the importance of each transition is measured. A reasonable approach is to use the magnitude of a transition’s TD error $\\delta$, which indicates how ‘surprising’\n",
    "or unexpected the transition is. This algorithm stores the last encountered TD error along with each transition in the replay memory. The transition with the largest absolute TD error is replayed from the memory. A Q-learning update\n",
    "is applied to this transition, which updates the weights in proportion to the TD error. One thing to note that new transitions arrive without a known TD-error, so it puts them at maximal priority in order to guarantee that all experience is seen at least once. (see *store* method)\n",
    "\n",
    "We might use 2 ideas to deal with TD-error: 1. greedy TD-error prioritization, 2. stochastic prioritization. However, greedy TD-error prioritization has a severe drawback. Greedy prioritization focuses on a small subset of the experience: errors shrink slowly, especially when using function approximation, meaning that the initially high error transitions get replayed frequently. This lack of diversity that makes the system prone to over-fitting. To overcome this issue, we will use a stochastic sampling method that interpolates between pure greedy prioritization and uniform random sampling.\n",
    "\n",
    "$$\n",
    "P(i) = \\frac{p_i^{\\alpha}}{\\sum_k p_k^{\\alpha}}\n",
    "$$\n",
    "\n",
    "where $p_i > 0$ is the priority of transition $i$. The exponent $\\alpha$ determines how much prioritization is used, with $\\alpha = 0$ corresponding to the uniform case. In practice, we use additional term $\\epsilon$ in order to guarantee all transactions can be possibly sampled: $p_i = |\\delta_i| + \\epsilon$, where $\\epsilon$ is a small positive constant.\n",
    "\n",
    "One more. Let's recall one of the main ideas of DQN. To remove correlation of observations, it uses uniformly random sampling from the replay buffer. Prioritized replay introduces bias because it doesn't sample experiences uniformly at random due to the sampling proportion correspoding to TD-error. We can correct this bias by using importance-sampling (IS) weights\n",
    "\n",
    "$$\n",
    "w_i = \\big( \\frac{1}{N} \\cdot \\frac{1}{P(i)} \\big)^\\beta\n",
    "$$\n",
    "\n",
    "that fully compensates for the non-uniform probabilities $P(i)$ if $\\beta = 1$. These weights can be folded into the Q-learning update by using $w_i\\delta_i$ instead of $\\delta_i$. In typical reinforcement learning scenarios, the unbiased nature of the updates is most important near convergence at the end of training, We therefore exploit the flexibility of annealing the amount of importance-sampling correction over time, by defining a schedule on the exponent $\\beta$ that reaches 1 only at the end of learning. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import random\n",
    "from typing import Dict, List, Tuple\n",
    "\n",
    "import gym\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "import torch.optim as optim\n",
    "from IPython.display import clear_output\n",
    "\n",
    "if IN_COLAB and not os.path.exists(\"segment_tree.py\"):\n",
    "    # download segment tree module\n",
    "    !wget https://raw.githubusercontent.com/curt-park/rainbow-is-all-you-need/master/segment_tree.py\n",
    "        \n",
    "from segment_tree import MinSegmentTree, SumSegmentTree"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Replay buffer\n",
    "\n",
    "Please see *01.dqn.ipynb* for detailed description."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ReplayBuffer:\n",
    "    \"\"\"A simple numpy replay buffer.\"\"\"\n",
    "\n",
    "    def __init__(self, obs_dim: int, size: int, batch_size: int = 32):\n",
    "        self.obs_buf = np.zeros([size, obs_dim], dtype=np.float32)\n",
    "        self.next_obs_buf = np.zeros([size, obs_dim], dtype=np.float32)\n",
    "        self.acts_buf = np.zeros([size], dtype=np.float32)\n",
    "        self.rews_buf = np.zeros([size], dtype=np.float32)\n",
    "        self.done_buf = np.zeros(size, dtype=np.float32)\n",
    "        self.max_size, self.batch_size = size, batch_size\n",
    "        self.ptr, self.size, = 0, 0\n",
    "\n",
    "    def store(\n",
    "        self,\n",
    "        obs: np.ndarray,\n",
    "        act: np.ndarray, \n",
    "        rew: float, \n",
    "        next_obs: np.ndarray, \n",
    "        done: bool,\n",
    "    ):\n",
    "        self.obs_buf[self.ptr] = obs\n",
    "        self.next_obs_buf[self.ptr] = next_obs\n",
    "        self.acts_buf[self.ptr] = act\n",
    "        self.rews_buf[self.ptr] = rew\n",
    "        self.done_buf[self.ptr] = done\n",
    "        self.ptr = (self.ptr + 1) % self.max_size\n",
    "        self.size = min(self.size + 1, self.max_size)\n",
    "\n",
    "    def sample_batch(self) -> Dict[str, np.ndarray]:\n",
    "        idxs = np.random.choice(self.size, size=self.batch_size, replace=False)\n",
    "        return dict(obs=self.obs_buf[idxs],\n",
    "                    next_obs=self.next_obs_buf[idxs],\n",
    "                    acts=self.acts_buf[idxs],\n",
    "                    rews=self.rews_buf[idxs],\n",
    "                    done=self.done_buf[idxs])\n",
    "\n",
    "    def __len__(self) -> int:\n",
    "        return self.size"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Prioritized replay Buffer\n",
    "\n",
    "The key concept of PER's implementation is *Segment Tree*. It efficiently stores and samples transitions while managing the priorities of them. We recommend you understand how it works before you move on. Here are references for you:\n",
    "\n",
    "- In Korean: https://mrsyee.github.io/rl/2019/01/25/PER-sumtree/\n",
    "- In English: https://www.geeksforgeeks.org/segment-tree-set-1-sum-of-given-range/"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "class PrioritizedReplayBuffer(ReplayBuffer):\n",
    "    \"\"\"Prioritized Replay buffer.\n",
    "    \n",
    "    Attributes:\n",
    "        max_priority (float): max priority\n",
    "        tree_ptr (int): next index of tree\n",
    "        alpha (float): alpha parameter for prioritized replay buffer\n",
    "        sum_tree (SumSegmentTree): sum tree for prior\n",
    "        min_tree (MinSegmentTree): min tree for min prior to get max weight\n",
    "        \n",
    "    \"\"\"\n",
    "    \n",
    "    def __init__(\n",
    "        self, \n",
    "        obs_dim: int,\n",
    "        size: int, \n",
    "        batch_size: int = 32, \n",
    "        alpha: float = 0.6\n",
    "    ):\n",
    "        \"\"\"Initialization.\"\"\"\n",
    "        assert alpha >= 0\n",
    "        \n",
    "        super(PrioritizedReplayBuffer, self).__init__(obs_dim, size, batch_size)\n",
    "        self.max_priority, self.tree_ptr = 1.0, 0\n",
    "        self.alpha = alpha\n",
    "        \n",
    "        # capacity must be positive and a power of 2.\n",
    "        tree_capacity = 1\n",
    "        while tree_capacity < self.max_size:\n",
    "            tree_capacity *= 2\n",
    "\n",
    "        self.sum_tree = SumSegmentTree(tree_capacity)\n",
    "        self.min_tree = MinSegmentTree(tree_capacity)\n",
    "        \n",
    "    def store(\n",
    "        self, \n",
    "        obs: np.ndarray, \n",
    "        act: int, \n",
    "        rew: float, \n",
    "        next_obs: np.ndarray, \n",
    "        done: bool\n",
    "    ):\n",
    "        \"\"\"Store experience and priority.\"\"\"\n",
    "        super().store(obs, act, rew, next_obs, done)\n",
    "        \n",
    "        self.sum_tree[self.tree_ptr] = self.max_priority ** self.alpha\n",
    "        self.min_tree[self.tree_ptr] = self.max_priority ** self.alpha\n",
    "        self.tree_ptr = (self.tree_ptr + 1) % self.max_size\n",
    "\n",
    "    def sample_batch(self, beta: float = 0.4) -> Dict[str, np.ndarray]:\n",
    "        \"\"\"Sample a batch of experiences.\"\"\"\n",
    "        assert len(self) >= self.batch_size\n",
    "        assert beta > 0\n",
    "        \n",
    "        indices = self._sample_proportional()\n",
    "        \n",
    "        obs = self.obs_buf[indices]\n",
    "        next_obs = self.next_obs_buf[indices]\n",
    "        acts = self.acts_buf[indices]\n",
    "        rews = self.rews_buf[indices]\n",
    "        done = self.done_buf[indices]\n",
    "        weights = np.array([self._calculate_weight(i, beta) for i in indices])\n",
    "        \n",
    "        return dict(\n",
    "            obs=obs,\n",
    "            next_obs=next_obs,\n",
    "            acts=acts,\n",
    "            rews=rews,\n",
    "            done=done,\n",
    "            weights=weights,\n",
    "            indices=indices,\n",
    "        )\n",
    "        \n",
    "    def update_priorities(self, indices: List[int], priorities: np.ndarray):\n",
    "        \"\"\"Update priorities of sampled transitions.\"\"\"\n",
    "        assert len(indices) == len(priorities)\n",
    "\n",
    "        for idx, priority in zip(indices, priorities):\n",
    "            assert priority > 0\n",
    "            assert 0 <= idx < len(self)\n",
    "\n",
    "            self.sum_tree[idx] = priority ** self.alpha\n",
    "            self.min_tree[idx] = priority ** self.alpha\n",
    "\n",
    "            self.max_priority = max(self.max_priority, priority)\n",
    "            \n",
    "    def _sample_proportional(self) -> List[int]:\n",
    "        \"\"\"Sample indices based on proportions.\"\"\"\n",
    "        indices = []\n",
    "        p_total = self.sum_tree.sum(0, len(self) - 1)\n",
    "        segment = p_total / self.batch_size\n",
    "        \n",
    "        for i in range(self.batch_size):\n",
    "            a = segment * i\n",
    "            b = segment * (i + 1)\n",
    "            upperbound = random.uniform(a, b)\n",
    "            idx = self.sum_tree.retrieve(upperbound)\n",
    "            indices.append(idx)\n",
    "            \n",
    "        return indices\n",
    "    \n",
    "    def _calculate_weight(self, idx: int, beta: float):\n",
    "        \"\"\"Calculate the weight of the experience at idx.\"\"\"\n",
    "        # get max weight\n",
    "        p_min = self.min_tree.min() / self.sum_tree.sum()\n",
    "        max_weight = (p_min * len(self)) ** (-beta)\n",
    "        \n",
    "        # calculate weights\n",
    "        p_sample = self.sum_tree[idx] / self.sum_tree.sum()\n",
    "        weight = (p_sample * len(self)) ** (-beta)\n",
    "        weight = weight / max_weight\n",
    "        \n",
    "        return weight"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Network\n",
    "\n",
    "We are going to use a simple network architecture with three fully connected layers and two non-linearity functions (ReLU)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Network(nn.Module):\n",
    "    def __init__(self, in_dim: int, out_dim: int):\n",
    "        \"\"\"Initialization.\"\"\"\n",
    "        super(Network, self).__init__()\n",
    "\n",
    "        self.layers = nn.Sequential(\n",
    "            nn.Linear(in_dim, 128), \n",
    "            nn.ReLU(),\n",
    "            nn.Linear(128, 128), \n",
    "            nn.ReLU(), \n",
    "            nn.Linear(128, out_dim)\n",
    "        )\n",
    "\n",
    "    def forward(self, x: torch.Tensor) -> torch.Tensor:\n",
    "        \"\"\"Forward method implementation.\"\"\"\n",
    "        return self.layers(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## DQN + PER Agent\n",
    "\n",
    "Here is a summary of DQNAgent class.\n",
    "\n",
    "| Method           | Note                                                 |\n",
    "| ---              | ---                                                  |\n",
    "|select_action     | select an action from the input state.               |\n",
    "|step              | take an action and return the response of the env.   |\n",
    "|compute_dqn_loss  | return dqn loss.                                     |\n",
    "|update_model      | update the model by gradient descent.                |\n",
    "|target_hard_update| hard update from the local model to the target model.|\n",
    "|train             | train the agent during num_frames.                   |\n",
    "|test              | test the agent (1 episode).                          |\n",
    "|plot              | plot the training progresses.                        |\n",
    "\n",
    "\n",
    "All differences from pure DQN are noted with comments - PER.\n",
    "\n",
    "#### __init__\n",
    "\n",
    "Here, we use PrioritizedReplayBuffer, instead of ReplayBuffer, and use hold 2 more parameters beta and priority epsilon which are used to calculate weights and new priorities respectively.\n",
    "\n",
    "#### compute_dqn_loss & update_model\n",
    "\n",
    "It returns every loss per each sample for importance sampling before average. After updating the nework, it is necessary to update priorities of all sampled experiences.\n",
    "\n",
    "#### train\n",
    "\n",
    "beta linearly increases to 1 at every training step."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "class DQNAgent:\n",
    "    \"\"\"DQN Agent interacting with environment.\n",
    "    \n",
    "    Attribute:\n",
    "        env (gym.Env): openAI Gym environment\n",
    "        memory (ReplayBuffer): replay memory to store transitions\n",
    "        batch_size (int): batch size for sampling\n",
    "        epsilon (float): parameter for epsilon greedy policy\n",
    "        epsilon_decay (float): step size to decrease epsilon\n",
    "        max_epsilon (float): max value of epsilon\n",
    "        min_epsilon (float): min value of epsilon\n",
    "        target_update (int): period for target model's hard update\n",
    "        gamma (float): discount factor\n",
    "        dqn (Network): model to train and select actions\n",
    "        dqn_target (Network): target model to update\n",
    "        optimizer (torch.optim): optimizer for training dqn\n",
    "        transition (list): transition information including \n",
    "                           state, action, reward, next_state, done\n",
    "        beta (float): determines how much importance sampling is used\n",
    "        prior_eps (float): guarantees every transition can be sampled\n",
    "    \"\"\"\n",
    "\n",
    "    def __init__(\n",
    "        self, \n",
    "        env: gym.Env,\n",
    "        memory_size: int,\n",
    "        batch_size: int,\n",
    "        target_update: int,\n",
    "        epsilon_decay: float,\n",
    "        max_epsilon: float = 1.0,\n",
    "        min_epsilon: float = 0.1,\n",
    "        gamma: float = 0.99,\n",
    "        # PER parameters\n",
    "        alpha: float = 0.2,\n",
    "        beta: float = 0.6,\n",
    "        prior_eps: float = 1e-6,\n",
    "    ):\n",
    "        \"\"\"Initialization.\n",
    "        \n",
    "        Args:\n",
    "            env (gym.Env): openAI Gym environment\n",
    "            memory_size (int): length of memory\n",
    "            batch_size (int): batch size for sampling\n",
    "            target_update (int): period for target model's hard update\n",
    "            epsilon_decay (float): step size to decrease epsilon\n",
    "            lr (float): learning rate\n",
    "            max_epsilon (float): max value of epsilon\n",
    "            min_epsilon (float): min value of epsilon\n",
    "            gamma (float): discount factor\n",
    "            alpha (float): determines how much prioritization is used\n",
    "            beta (float): determines how much importance sampling is used\n",
    "            prior_eps (float): guarantees every transition can be sampled\n",
    "        \"\"\"\n",
    "        obs_dim = env.observation_space.shape[0]\n",
    "        action_dim = env.action_space.n\n",
    "        \n",
    "        self.env = env\n",
    "        \n",
    "        self.batch_size = batch_size\n",
    "        self.epsilon = max_epsilon\n",
    "        self.epsilon_decay = epsilon_decay\n",
    "        self.max_epsilon = max_epsilon\n",
    "        self.min_epsilon = min_epsilon\n",
    "        self.target_update = target_update\n",
    "        self.gamma = gamma\n",
    "        \n",
    "        # device: cpu / gpu\n",
    "        self.device = torch.device(\n",
    "            \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
    "        )\n",
    "        print(self.device)\n",
    "        \n",
    "        # PER\n",
    "        # In DQN, We used \"ReplayBuffer(obs_dim, memory_size, batch_size)\"\n",
    "        self.beta = beta\n",
    "        self.prior_eps = prior_eps\n",
    "        self.memory = PrioritizedReplayBuffer(\n",
    "            obs_dim, memory_size, batch_size, alpha\n",
    "        )\n",
    "\n",
    "        # networks: dqn, dqn_target\n",
    "        self.dqn = Network(obs_dim, action_dim).to(self.device)\n",
    "        self.dqn_target = Network(obs_dim, action_dim).to(self.device)\n",
    "        self.dqn_target.load_state_dict(self.dqn.state_dict())\n",
    "        self.dqn_target.eval()\n",
    "        \n",
    "        # optimizer\n",
    "        self.optimizer = optim.Adam(self.dqn.parameters())\n",
    "\n",
    "        # transition to store in memory\n",
    "        self.transition = list()\n",
    "        \n",
    "        # mode: train / test\n",
    "        self.is_test = False\n",
    "\n",
    "    def select_action(self, state: np.ndarray) -> np.ndarray:\n",
    "        \"\"\"Select an action from the input state.\"\"\"\n",
    "        # epsilon greedy policy\n",
    "        if self.epsilon > np.random.random():\n",
    "            selected_action = self.env.action_space.sample()\n",
    "        else:\n",
    "            selected_action = self.dqn(\n",
    "                torch.FloatTensor(state).to(self.device)\n",
    "            ).argmax()\n",
    "            selected_action = selected_action.detach().cpu().numpy()\n",
    "        \n",
    "        if not self.is_test:\n",
    "            self.transition = [state, selected_action]\n",
    "        \n",
    "        return selected_action\n",
    "\n",
    "    def step(self, action: np.ndarray) -> Tuple[np.ndarray, np.float64, bool]:\n",
    "        \"\"\"Take an action and return the response of the env.\"\"\"\n",
    "        next_state, reward, done, _ = self.env.step(action)\n",
    "\n",
    "        if not self.is_test:\n",
    "            self.transition += [reward, next_state, done]\n",
    "            self.memory.store(*self.transition)\n",
    "    \n",
    "        return next_state, reward, done\n",
    "\n",
    "    def update_model(self) -> torch.Tensor:\n",
    "        \"\"\"Update the model by gradient descent.\"\"\"\n",
    "        # PER needs beta to calculate weights\n",
    "        samples = self.memory.sample_batch(self.beta)\n",
    "        weights = torch.FloatTensor(\n",
    "            samples[\"weights\"].reshape(-1, 1)\n",
    "        ).to(self.device)\n",
    "        indices = samples[\"indices\"]\n",
    "\n",
    "        # PER: importance sampling before average\n",
    "        elementwise_loss = self._compute_dqn_loss(samples)\n",
    "        loss = torch.mean(elementwise_loss * weights)\n",
    "\n",
    "        self.optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        self.optimizer.step()\n",
    "        \n",
    "        # PER: update priorities\n",
    "        loss_for_prior = elementwise_loss.detach().cpu().numpy()\n",
    "        new_priorities = loss_for_prior + self.prior_eps\n",
    "        self.memory.update_priorities(indices, new_priorities)\n",
    "\n",
    "        return loss.item()\n",
    "        \n",
    "    def train(self, num_frames: int, plotting_interval: int = 200):\n",
    "        \"\"\"Train the agent.\"\"\"\n",
    "        self.is_test = False\n",
    "        \n",
    "        state = self.env.reset()\n",
    "        update_cnt = 0\n",
    "        epsilons = []\n",
    "        losses = []\n",
    "        scores = []\n",
    "        score = 0\n",
    "\n",
    "        for frame_idx in range(1, num_frames + 1):\n",
    "            action = self.select_action(state)\n",
    "            next_state, reward, done = self.step(action)\n",
    "\n",
    "            state = next_state\n",
    "            score += reward\n",
    "            \n",
    "            # PER: increase beta\n",
    "            fraction = min(frame_idx / num_frames, 1.0)\n",
    "            self.beta = self.beta + fraction * (1.0 - self.beta)\n",
    "\n",
    "            # if episode ends\n",
    "            if done:\n",
    "                state = self.env.reset()\n",
    "                scores.append(score)\n",
    "                score = 0\n",
    "\n",
    "            # if training is ready\n",
    "            if len(self.memory) >= self.batch_size:\n",
    "                loss = self.update_model()\n",
    "                losses.append(loss)\n",
    "                update_cnt += 1\n",
    "                \n",
    "                # linearly decrease epsilon\n",
    "                self.epsilon = max(\n",
    "                    self.min_epsilon, self.epsilon - (\n",
    "                        self.max_epsilon - self.min_epsilon\n",
    "                    ) * self.epsilon_decay\n",
    "                )\n",
    "                epsilons.append(self.epsilon)\n",
    "                \n",
    "                # if hard update is needed\n",
    "                if update_cnt % self.target_update == 0:\n",
    "                    self._target_hard_update()\n",
    "\n",
    "            # plotting\n",
    "            if frame_idx % plotting_interval == 0:\n",
    "                self._plot(frame_idx, scores, losses, epsilons)\n",
    "                \n",
    "        self.env.close()\n",
    "                \n",
    "    def test(self) -> List[np.ndarray]:\n",
    "        \"\"\"Test the agent.\"\"\"\n",
    "        self.is_test = True\n",
    "        \n",
    "        state = self.env.reset()\n",
    "        done = False\n",
    "        score = 0\n",
    "        \n",
    "        frames = []\n",
    "        while not done:\n",
    "            frames.append(self.env.render(mode=\"rgb_array\"))\n",
    "            action = self.select_action(state)\n",
    "            next_state, reward, done = self.step(action)\n",
    "\n",
    "            state = next_state\n",
    "            score += reward\n",
    "        \n",
    "        print(\"score: \", score)\n",
    "        self.env.close()\n",
    "        \n",
    "        return frames\n",
    "\n",
    "    def _compute_dqn_loss(self, samples: Dict[str, np.ndarray]) -> torch.Tensor:\n",
    "        \"\"\"Return dqn loss.\"\"\"\n",
    "        device = self.device  # for shortening the following lines\n",
    "        state = torch.FloatTensor(samples[\"obs\"]).to(device)\n",
    "        next_state = torch.FloatTensor(samples[\"next_obs\"]).to(device)\n",
    "        action = torch.LongTensor(samples[\"acts\"].reshape(-1, 1)).to(device)\n",
    "        reward = torch.FloatTensor(samples[\"rews\"].reshape(-1, 1)).to(device)\n",
    "        done = torch.FloatTensor(samples[\"done\"].reshape(-1, 1)).to(device)\n",
    "\n",
    "        # G_t   = r + gamma * v(s_{t+1})  if state != Terminal\n",
    "        #       = r                       otherwise\n",
    "        curr_q_value = self.dqn(state).gather(1, action)\n",
    "        next_q_value = self.dqn_target(\n",
    "            next_state\n",
    "        ).max(dim=1, keepdim=True)[0].detach()\n",
    "        mask = 1 - done\n",
    "        target = (reward + self.gamma * next_q_value * mask).to(self.device)\n",
    "\n",
    "        # calculate element-wise dqn loss\n",
    "        elementwise_loss = F.smooth_l1_loss(curr_q_value, target, reduction=\"none\")\n",
    "\n",
    "        return elementwise_loss\n",
    "    \n",
    "    def _target_hard_update(self):\n",
    "        \"\"\"Hard update: target <- local.\"\"\"\n",
    "        self.dqn_target.load_state_dict(self.dqn.state_dict())\n",
    "                \n",
    "    def _plot(\n",
    "        self, \n",
    "        frame_idx: int, \n",
    "        scores: List[float], \n",
    "        losses: List[float], \n",
    "        epsilons: List[float],\n",
    "    ):\n",
    "        \"\"\"Plot the training progresses.\"\"\"\n",
    "        clear_output(True)\n",
    "        plt.figure(figsize=(20, 5))\n",
    "        plt.subplot(131)\n",
    "        plt.title('frame %s. score: %s' % (frame_idx, np.mean(scores[-10:])))\n",
    "        plt.plot(scores)\n",
    "        plt.subplot(132)\n",
    "        plt.title('loss')\n",
    "        plt.plot(losses)\n",
    "        plt.subplot(133)\n",
    "        plt.title('epsilons')\n",
    "        plt.plot(epsilons)\n",
    "        plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Environment\n",
    "\n",
    "You can see the [code](https://github.com/openai/gym/blob/master/gym/envs/classic_control/cartpole.py) and [configurations](https://github.com/openai/gym/blob/master/gym/envs/__init__.py#L53) of CartPole-v0 from OpenAI's repository."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# environment\n",
    "env_id = \"CartPole-v0\"\n",
    "env = gym.make(env_id)\n",
    "if IN_COLAB:\n",
    "    env = gym.wrappers.Monitor(env, \"videos\", force=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Set random seed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[777]"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "seed = 777\n",
    "\n",
    "def seed_torch(seed):\n",
    "    torch.manual_seed(seed)\n",
    "    if torch.backends.cudnn.enabled:\n",
    "        torch.backends.cudnn.benchmark = False\n",
    "        torch.backends.cudnn.deterministic = True\n",
    "\n",
    "np.random.seed(seed)\n",
    "random.seed(seed)\n",
    "seed_torch(seed)\n",
    "env.seed(seed)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Initialize"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "cpu\n"
     ]
    }
   ],
   "source": [
    "# parameters\n",
    "num_frames = 20000\n",
    "memory_size = 2000\n",
    "batch_size = 32\n",
    "target_update = 100\n",
    "epsilon_decay = 1 / 2000\n",
    "\n",
    "# train\n",
    "agent = DQNAgent(env, memory_size, batch_size, target_update, epsilon_decay)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Train"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 1440x360 with 3 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "agent.train(num_frames)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Test\n",
    "\n",
    "Run the trained agent (1 episode)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "score:  200.0\n"
     ]
    }
   ],
   "source": [
    "frames = agent.test()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Render"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<script language=\"javascript\">\n",
       "  /* Define the Animation class */\n",
       "  function Animation(frames, img_id, slider_id, interval, loop_select_id){\n",
       "    this.img_id = img_id;\n",
       "    this.slider_id = slider_id;\n",
       "    this.loop_select_id = loop_select_id;\n",
       "    this.interval = interval;\n",
       "    this.current_frame = 0;\n",
       "    this.direction = 0;\n",
       "    this.timer = null;\n",
       "    this.frames = new Array(frames.length);\n",
       "\n",
       "    for (var i=0; i<frames.length; i++)\n",
       "    {\n",
       "     this.frames[i] = new Image();\n",
       "     this.frames[i].src = frames[i];\n",
       "    }\n",
       "    document.getElementById(this.slider_id).max = this.frames.length - 1;\n",
       "    this.set_frame(this.current_frame);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.get_loop_state = function(){\n",
       "    var button_group = document[this.loop_select_id].state;\n",
       "    for (var i = 0; i < button_group.length; i++) {\n",
       "        var button = button_group[i];\n",
       "        if (button.checked) {\n",
       "            return button.value;\n",
       "        }\n",
       "    }\n",
       "    return undefined;\n",
       "  }\n",
       "\n",
       "  Animation.prototype.set_frame = function(frame){\n",
       "    this.current_frame = frame;\n",
       "    document.getElementById(this.img_id).src = this.frames[this.current_frame].src;\n",
       "    document.getElementById(this.slider_id).value = this.current_frame;\n",
       "  }\n",
       "\n",
       "  Animation.prototype.next_frame = function()\n",
       "  {\n",
       "    this.set_frame(Math.min(this.frames.length - 1, this.current_frame + 1));\n",
       "  }\n",
       "\n",
       "  Animation.prototype.previous_frame = function()\n",
       "  {\n",
       "    this.set_frame(Math.max(0, this.current_frame - 1));\n",
       "  }\n",
       "\n",
       "  Animation.prototype.first_frame = function()\n",
       "  {\n",
       "    this.set_frame(0);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.last_frame = function()\n",
       "  {\n",
       "    this.set_frame(this.frames.length - 1);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.slower = function()\n",
       "  {\n",
       "    this.interval /= 0.7;\n",
       "    if(this.direction > 0){this.play_animation();}\n",
       "    else if(this.direction < 0){this.reverse_animation();}\n",
       "  }\n",
       "\n",
       "  Animation.prototype.faster = function()\n",
       "  {\n",
       "    this.interval *= 0.7;\n",
       "    if(this.direction > 0){this.play_animation();}\n",
       "    else if(this.direction < 0){this.reverse_animation();}\n",
       "  }\n",
       "\n",
       "  Animation.prototype.anim_step_forward = function()\n",
       "  {\n",
       "    this.current_frame += 1;\n",
       "    if(this.current_frame < this.frames.length){\n",
       "      this.set_frame(this.current_frame);\n",
       "    }else{\n",
       "      var loop_state = this.get_loop_state();\n",
       "      if(loop_state == \"loop\"){\n",
       "        this.first_frame();\n",
       "      }else if(loop_state == \"reflect\"){\n",
       "        this.last_frame();\n",
       "        this.reverse_animation();\n",
       "      }else{\n",
       "        this.pause_animation();\n",
       "        this.last_frame();\n",
       "      }\n",
       "    }\n",
       "  }\n",
       "\n",
       "  Animation.prototype.anim_step_reverse = function()\n",
       "  {\n",
       "    this.current_frame -= 1;\n",
       "    if(this.current_frame >= 0){\n",
       "      this.set_frame(this.current_frame);\n",
       "    }else{\n",
       "      var loop_state = this.get_loop_state();\n",
       "      if(loop_state == \"loop\"){\n",
       "        this.last_frame();\n",
       "      }else if(loop_state == \"reflect\"){\n",
       "        this.first_frame();\n",
       "        this.play_animation();\n",
       "      }else{\n",
       "        this.pause_animation();\n",
       "        this.first_frame();\n",
       "      }\n",
       "    }\n",
       "  }\n",
       "\n",
       "  Animation.prototype.pause_animation = function()\n",
       "  {\n",
       "    this.direction = 0;\n",
       "    if (this.timer){\n",
       "      clearInterval(this.timer);\n",
       "      this.timer = null;\n",
       "    }\n",
       "  }\n",
       "\n",
       "  Animation.prototype.play_animation = function()\n",
       "  {\n",
       "    this.pause_animation();\n",
       "    this.direction = 1;\n",
       "    var t = this;\n",
       "    if (!this.timer) this.timer = setInterval(function(){t.anim_step_forward();}, this.interval);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.reverse_animation = function()\n",
       "  {\n",
       "    this.pause_animation();\n",
       "    this.direction = -1;\n",
       "    var t = this;\n",
       "    if (!this.timer) this.timer = setInterval(function(){t.anim_step_reverse();}, this.interval);\n",
       "  }\n",
       "</script>\n",
       "\n",
       "<div class=\"animation\" align=\"center\">\n",
       "    <img id=\"_anim_imgSHJGZTUHPNCFVKAZ\">\n",
       "    <br>\n",
       "    <input id=\"_anim_sliderSHJGZTUHPNCFVKAZ\" type=\"range\" style=\"width:350px\" name=\"points\" min=\"0\" max=\"1\" step=\"1\" value=\"0\" onchange=\"animSHJGZTUHPNCFVKAZ.set_frame(parseInt(this.value));\"></input>\n",
       "    <br>\n",
       "    <button onclick=\"animSHJGZTUHPNCFVKAZ.slower()\">&#8211;</button>\n",
       "    <button onclick=\"animSHJGZTUHPNCFVKAZ.first_frame()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animSHJGZTUHPNCFVKAZ.previous_frame()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animSHJGZTUHPNCFVKAZ.reverse_animation()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animSHJGZTUHPNCFVKAZ.pause_animation()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animSHJGZTUHPNCFVKAZ.play_animation()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animSHJGZTUHPNCFVKAZ.next_frame()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animSHJGZTUHPNCFVKAZ.last_frame()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animSHJGZTUHPNCFVKAZ.faster()\">+</button>\n",
       "  <form action=\"#n\" name=\"_anim_loop_selectSHJGZTUHPNCFVKAZ\" class=\"anim_control\">\n",
       "    <input type=\"radio\" name=\"state\" value=\"once\" > Once </input>\n",
       "    <input type=\"radio\" name=\"state\" value=\"loop\" checked> Loop </input>\n",
       "    <input type=\"radio\" name=\"state\" value=\"reflect\" > Reflect </input>\n",
       "  </form>\n",
       "</div>\n",
       "\n",
       "\n",
       "<script language=\"javascript\">\n",
       "  /* Instantiate the Animation class. */\n",
       "  /* The IDs given should match those used in the template above. */\n",
       "  (function() {\n",
       "    var img_id = \"_anim_imgSHJGZTUHPNCFVKAZ\";\n",
       "    var slider_id = \"_anim_sliderSHJGZTUHPNCFVKAZ\";\n",
       "    var loop_select_id = \"_anim_loop_selectSHJGZTUHPNCFVKAZ\";\n",
       "    var frames = new Array(0);\n",
       "    \n",
       "  frames[0] = \"\"\n",
       "  frames[1] = \"\"\n",
       "  frames[2] = \"\"\n",
       "  frames[3] = \"\"\n",
       "  frames[4] = \"\"\n",
       "  frames[5] = \"\"\n",
       "  frames[6] = \"\"\n",
       "  frames[7] = \"\"\n",
       "  frames[8] = \"\"\n",
       "  frames[9] = \"\"\n",
       "  frames[10] = \"\"\n",
       "  frames[11] = \"\"\n",
       "  frames[12] = \"\"\n",
       "  frames[13] = \"\"\n",
       "  frames[14] = \"\"\n",
       "  frames[15] = \"\"\n",
       "  frames[16] = \"\"\n",
       "  frames[17] = \"\"\n",
       "  frames[18] = \"\"\n",
       "  frames[19] = \"\"\n",
       "  frames[20] = \"\"\n",
       "  frames[21] = \"\"\n",
       "  frames[22] = \"\"\n",
       "  frames[23] = \"\"\n",
       "  frames[24] = \"\"\n",
       "  frames[25] = \"\"\n",
       "  frames[26] = \"\"\n",
       "  frames[27] = \"\"\n",
       "  frames[28] = \"\"\n",
       "  frames[29] = \"\"\n",
       "  frames[30] = \"\"\n",
       "  frames[31] = \"\"\n",
       "  frames[32] = \"\"\n",
       "  frames[33] = \"\"\n",
       "  frames[34] = \"\"\n",
       "  frames[35] = \"\"\n",
       "  frames[36] = \"\"\n",
       "  frames[37] = \"\"\n",
       "  frames[38] = \"\"\n",
       "  frames[39] = \"\"\n",
       "  frames[40] = \"\"\n",
       "  frames[41] = \"\"\n",
       "  frames[42] = \"\"\n",
       "  frames[43] = \"\"\n",
       "  frames[44] = \"\"\n",
       "  frames[45] = \"\"\n",
       "  frames[46] = \"\"\n",
       "  frames[47] = \"\"\n",
       "  frames[48] = \"\"\n",
       "  frames[49] = \"\"\n",
       "  frames[50] = \"\"\n",
       "  frames[51] = \"\"\n",
       "  frames[52] = \"\"\n",
       "  frames[53] = \"\"\n",
       "  frames[54] = \"\"\n",
       "  frames[55] = \"\"\n",
       "  frames[56] = \"\"\n",
       "  frames[57] = \"\"\n",
       "  frames[58] = \"\"\n",
       "  frames[59] = \"\"\n",
       "  frames[60] = \"\"\n",
       "  frames[61] = \"\"\n",
       "  frames[62] = \"\"\n",
       "  frames[63] = \"\"\n",
       "  frames[64] = \"\"\n",
       "  frames[65] = \"\"\n",
       "  frames[66] = \"\"\n",
       "  frames[67] = \"\"\n",
       "  frames[68] = \"\"\n",
       "  frames[69] = \"\"\n",
       "  frames[70] = \"\"\n",
       "  frames[71] = \"\"\n",
       "  frames[72] = \"\"\n",
       "  frames[73] = \"\"\n",
       "  frames[74] = \"\"\n",
       "  frames[75] = \"\"\n",
       "  frames[76] = \"\"\n",
       "  frames[77] = \"\"\n",
       "  frames[78] = \"\"\n",
       "  frames[79] = \"\"\n",
       "  frames[80] = \"\"\n",
       "  frames[81] = \"\"\n",
       "  frames[82] = \"\"\n",
       "  frames[83] = \"\"\n",
       "  frames[84] = \"\"\n",
       "  frames[85] = \"\"\n",
       "  frames[86] = \"\"\n",
       "  frames[87] = \"\"\n",
       "  frames[88] = \"\"\n",
       "  frames[89] = \"\"\n",
       "  frames[90] = \"\"\n",
       "  frames[91] = \"\"\n",
       "  frames[92] = \"\"\n",
       "  frames[93] = \"\"\n",
       "  frames[94] = \"\"\n",
       "  frames[95] = \"\"\n",
       "  frames[96] = \"\"\n",
       "  frames[97] = \"\"\n",
       "  frames[98] = \"\"\n",
       "  frames[99] = \"\"\n",
       "  frames[100] = \"\"\n",
       "  frames[101] = \"\"\n",
       "  frames[102] = \"\"\n",
       "  frames[103] = \"\"\n",
       "  frames[104] = \"\"\n",
       "  frames[105] = \"\"\n",
       "  frames[106] = \"\"\n",
       "  frames[107] = \"\"\n",
       "  frames[108] = \"\"\n",
       "  frames[109] = \"\"\n",
       "  frames[110] = \"\"\n",
       "  frames[111] = \"\"\n",
       "  frames[112] = \"\"\n",
       "  frames[113] = \"\"\n",
       "  frames[114] = \"\"\n",
       "  frames[115] = \"\"\n",
       "  frames[116] = \"\"\n",
       "  frames[117] = \"\"\n",
       "  frames[118] = \"\"\n",
       "  frames[119] = \"\"\n",
       "  frames[120] = \"\"\n",
       "  frames[121] = \"\"\n",
       "  frames[122] = \"\"\n",
       "  frames[123] = \"\"\n",
       "  frames[124] = \"\"\n",
       "  frames[125] = \"\"\n",
       "  frames[126] = \"\"\n",
       "  frames[127] = \"\"\n",
       "  frames[128] = \"\"\n",
       "  frames[129] = \"\"\n",
       "  frames[130] = \"\"\n",
       "  frames[131] = \"\"\n",
       "  frames[132] = \"\"\n",
       "  frames[133] = \"\"\n",
       "  frames[134] = \"\"\n",
       "  frames[135] = \"\"\n",
       "  frames[136] = \"\"\n",
       "  frames[137] = \"\"\n",
       "  frames[138] = \"\"\n",
       "  frames[139] = \"\"\n",
       "  frames[140] = \"\"\n",
       "  frames[141] = \"\"\n",
       "  frames[142] = \"\"\n",
       "  frames[143] = \"\"\n",
       "  frames[144] = \"\"\n",
       "  frames[145] = \"\"\n",
       "  frames[146] = \"\"\n",
       "  frames[147] = \"\"\n",
       "  frames[148] = \"\"\n",
       "  frames[149] = \"\"\n",
       "  frames[150] = \"\"\n",
       "  frames[151] = \"\"\n",
       "  frames[152] = \"\"\n",
       "  frames[153] = \"\"\n",
       "  frames[154] = \"\"\n",
       "  frames[155] = \"\"\n",
       "  frames[156] = \"\"\n",
       "  frames[157] = \"\"\n",
       "  frames[158] = \"\"\n",
       "  frames[159] = \"\"\n",
       "  frames[160] = \"\"\n",
       "  frames[161] = \"\"\n",
       "  frames[162] = \"\"\n",
       "  frames[163] = \"\"\n",
       "  frames[164] = \"\"\n",
       "  frames[165] = \"\"\n",
       "  frames[166] = \"\"\n",
       "  frames[167] = \"\"\n",
       "  frames[168] = \"\"\n",
       "  frames[169] = \"\"\n",
       "  frames[170] = \"\"\n",
       "  frames[171] = \"\"\n",
       "  frames[172] = \"\"\n",
       "  frames[173] = \"\"\n",
       "  frames[174] = \"\"\n",
       "  frames[175] = \"\"\n",
       "  frames[176] = \"\"\n",
       "  frames[177] = \"\"\n",
       "  frames[178] = \"\"\n",
       "  frames[179] = \"\"\n",
       "  frames[180] = \"\"\n",
       "  frames[181] = \"\"\n",
       "  frames[182] = \"\"\n",
       "  frames[183] = \"\"\n",
       "  frames[184] = \"\"\n",
       "  frames[185] = \"\"\n",
       "  frames[186] = \"\"\n",
       "  frames[187] = \"\"\n",
       "  frames[188] = \"\"\n",
       "  frames[189] = \"\"\n",
       "  frames[190] = \"\"\n",
       "  frames[191] = \"\"\n",
       "  frames[192] = \"\"\n",
       "  frames[193] = \"\"\n",
       "  frames[194] = \"\"\n",
       "  frames[195] = \"\"\n",
       "  frames[196] = \"\"\n",
       "  frames[197] = \"\"\n",
       "  frames[198] = \"\"\n",
       "  frames[199] = \"\"\n",
       "\n",
       "\n",
       "    /* set a timeout to make sure all the above elements are created before\n",
       "       the object is initialized. */\n",
       "    setTimeout(function() {\n",
       "        animSHJGZTUHPNCFVKAZ = new Animation(frames, img_id, slider_id, 50, loop_select_id);\n",
       "    }, 0);\n",
       "  })()\n",
       "</script>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "if IN_COLAB:  # for colab\n",
    "    import base64\n",
    "    import glob\n",
    "    import io\n",
    "    import os\n",
    "\n",
    "    from IPython.display import HTML, display\n",
    "\n",
    "\n",
    "    def ipython_show_video(path: str) -> None:\n",
    "        \"\"\"Show a video at `path` within IPython Notebook.\"\"\"\n",
    "        if not os.path.isfile(path):\n",
    "            raise NameError(\"Cannot access: {}\".format(path))\n",
    "\n",
    "        video = io.open(path, \"r+b\").read()\n",
    "        encoded = base64.b64encode(video)\n",
    "\n",
    "        display(HTML(\n",
    "            data=\"\"\"\n",
    "            <video alt=\"test\" controls>\n",
    "            <source src=\"data:video/mp4;base64,{0}\" type=\"video/mp4\"/>\n",
    "            </video>\n",
    "            \"\"\".format(encoded.decode(\"ascii\"))\n",
    "        ))\n",
    "\n",
    "    list_of_files = glob.glob(\"videos/*.mp4\")\n",
    "    latest_file = max(list_of_files, key=os.path.getctime)\n",
    "    print(latest_file)\n",
    "    ipython_show_video(latest_file)\n",
    "\n",
    "else:  # for jupyter\n",
    "    from matplotlib import animation\n",
    "    from JSAnimation.IPython_display import display_animation\n",
    "    from IPython.display import display\n",
    "\n",
    "\n",
    "    def display_frames_as_gif(frames: List[np.ndarray]) -> None:\n",
    "        \"\"\"Displays a list of frames as a gif, with controls.\"\"\"\n",
    "        patch = plt.imshow(frames[0])\n",
    "        plt.axis('off')\n",
    "\n",
    "        def animate(i):\n",
    "            patch.set_data(frames[i])\n",
    "\n",
    "        anim = animation.FuncAnimation(\n",
    "            plt.gcf(), animate, frames = len(frames), interval=50\n",
    "        )\n",
    "        display(display_animation(anim, default_mode='loop'))\n",
    "\n",
    "\n",
    "    # display \n",
    "    display_frames_as_gif(frames)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
